{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Python 异常处理\n",
    "\n",
    "python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误。你可以使用该功能来调试python程序。\n",
    "\n",
    "1. 异常处理\n",
    "2. 断言(Assertions)\n",
    "\n",
    "\n",
    "### 什么是异常？\n",
    "\n",
    "异常即是一个事件，该事件会在程序执行过程中发生，影响了程序的正常执行。\n",
    "\n",
    "一般情况下，在Python无法正常处理程序时就会发生一个异常。\n",
    "\n",
    "异常是Python对象，表示一个错误。\n",
    "\n",
    "当Python脚本发生异常时我们需要捕获处理它，否则程序会终止执行"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "ename": "KeyError",
     "evalue": "'key'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mKeyError\u001b[0m                                  Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-1-9dac058c1fd4>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[0mempty_dict\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m{\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mempty_dict\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'key'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m  \u001b[1;31m# 这里代码就是有异常，异常叫“keyError”，然后程序终止\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mKeyError\u001b[0m: 'key'"
     ]
    }
   ],
   "source": [
    "empty_dict = {}\n",
    "print(empty_dict['key'])  # 这里代码就是有异常，异常叫“keyError”，然后程序终止"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### 异常处理\n",
    "\n",
    "捕捉异常可以使用try/except语句。\n",
    "\n",
    "try/except语句用来检测try语句块中的错误，从而让except语句捕获异常信息并处理。\n",
    "\n",
    "如果你不想在异常发生时结束你的程序，只需在try里捕获它。\n",
    "\n",
    "语法：\n",
    "\n",
    "以下为简单的try....except...else的语法：\n",
    "\n",
    "```\n",
    "try:\n",
    "<语句>        #运行别的代码\n",
    "except <名字>：\n",
    "<语句>        #如果在try部份引发了'name'异常\n",
    "except <名字>，<数据>:\n",
    "<语句>        #如果引发了'name'异常，获得附加的数据\n",
    "else:\n",
    "<语句>        #如果没有异常发生\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入键值key:name\n",
      "name值： 小琼\n",
      "输入正常\n"
     ]
    }
   ],
   "source": [
    "# 用异常处理来显示错误，程序就不会突然终止,比较友好的提示。\n",
    "dict1 = {\"name\":\"小琼\",\"age\":24}\n",
    "key_name = input(\"输入键值key:\")\n",
    "try:\n",
    "    print(f\"{key_name}值：\",dict1[key_name]) # 打印对应的值  f格式化输出{变量变}字符串\n",
    "except KeyError:\n",
    "    print(f\"输入错误,没有{key_name}键值\")\n",
    "else:\n",
    "    print(\"输入正常\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 练习1\n",
    "\n",
    "下面功能是把队列里面的数值求和，然后统计错误的数据。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def sum_of_list(values):\n",
    "    total = 0\n",
    "    for val in values:\n",
    "        ???:\n",
    "            numeric_val = float(val)\n",
    "        ??? ValueError as e:   # as e 可以理解为把e代替ValueError, 减少打字\n",
    "            print(\"数值错误,\", \"程序的提示输出\", e)\n",
    "        ???:\n",
    "            total += numeric_val\n",
    "    return total"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "float(\"fsf\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_list1 = ['11', 123, '2.7', '0']\n",
    "print(\"=======第一个=======\")\n",
    "print(sum_of_list(my_list1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_list2 = ['1a1', 123, '2..7', '1']\n",
    "print(\"=======第二个=======\")\n",
    "print(sum_of_list(my_list2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 多个异常\n",
    "\n",
    "```\n",
    "try:\n",
    "    正常的操作\n",
    "   ......................\n",
    "except(Exception1[, Exception2[,...ExceptionN]]]):\n",
    "   发生以上多个异常中的一个，执行这块代码\n",
    "   ......................\n",
    "except(Exception1[, Exception2[,...ExceptionN]]]):\n",
    "   写多个不同异常\n",
    "   ......................\n",
    "\n",
    "else:\n",
    "    如果没有异常执行这块代码\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def calculate_division(var1, var2):\n",
    "    # 除法函数\n",
    "    result = 0\n",
    "    try:\n",
    "        result = var1 / var2\n",
    "    except ZeroDivisionError as ex1:\n",
    "        print(\"被除数不能为0\")\n",
    "    except Exception as ex2:\n",
    "        print('其他错误: {}'.format(ex2))\n",
    "\n",
    "    return result\n",
    "\n",
    "result1 = calculate_division(3, 3)\n",
    "print('result1: {}'.format(result1))\n",
    "\n",
    "result2 = calculate_division(3, '3')\n",
    "print('result2: {}'.format(result2))\n",
    "\n",
    "result3 = calculate_division(3, 0)\n",
    "print('result3: {}'.format(result3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### try-finally 语句\n",
    "\n",
    "try-finally 语句无论是否发生异常都将执行最后的代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "empty_dict = {\"name\":\"小琼\",\"age\":24}\n",
    "key_name = input(\"输入键值key\")\n",
    "try:\n",
    "    print(f\"{key_name}值：\",empty_dict[key_name]) # 打印对应的值\n",
    "except KeyError:\n",
    "    print(f\"输入错误,没有{key_name}键值\")\n",
    "else:\n",
    "    print(\"输入正常\")\n",
    "finally:\n",
    "    print(\"这句话总数会出现\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 用户自定义异常\n",
    "\n",
    "通过创建一个新的异常类，程序可以命名它们自己的异常。异常应该是典型的继承自Exception类，通过直接或间接的方式。\n",
    "\n",
    "以下为与相关的实例,实例中创建了一个类，基类为Exception(异常类)，用于在异常触发时输出更多的信息。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "\n",
    "# 自定义错误\n",
    "class MyExceptionNegativeNumbersNotSupported(Exception):\n",
    "    pass # pass是什么都不做，只是定义了一个错误类型\n",
    "\n",
    "# 使用例子\n",
    "def secret_calculation(number1, number2):\n",
    "    if number1 < 0 or number2 < 0:\n",
    "        msg = '有负数在里面程序就不处理了: {}, {}'.format(number1, number2)\n",
    "        raise MyExceptionNegativeNumbersNotSupported(msg)\n",
    "\n",
    "    return math.sqrt(number1) + math.sqrt(number2)\n",
    "\n",
    "\n",
    "result = secret_calculation(-1, 1) # 故意引起错误"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 练习：猜数字游戏\n",
    "\n",
    "每次随机生成一个1-100内数字，猜一下是什么数字，如果输入不是1-100数字，设计一个异常处理，让程序继续等待一下个正常输入。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from random import randint  # 生成随机数\n",
    "min_number = 1\n",
    "max_number = 100\n",
    "luck_number = randint(min_number, max_number) # 生成一个随机数\n",
    "\n",
    "while ???:\n",
    "    input_number = input(f\"请输入{min_number}-{max_number}数字\")\n",
    "    try:\n",
    "        input_number = int(input_number)\n",
    "        \n",
    "        if luck_number == input_number:\n",
    "            print(f\"恭喜您猜中了，答案是{luck_number}\")\n",
    "            break # 跳出循环\n",
    "        elif luck_number > input_number:\n",
    "            min_number = input_number\n",
    "        else:\n",
    "            max_number = input_number\n",
    "    ??? ???:   # 处理异常\n",
    "            print(\"您输入的不是数字\")\n",
    "    else:\n",
    "        print(\"没有猜中，请继续\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 能完善一下程序吗？\n",
    "\n",
    "如果输入大于100的数字，或者小于1的数字，能不能处理更好"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
